Schemify
Overview

Plugin Overview

Schemify's plugin system lets you extend the editor without forking it. Plugins run as shared libraries (.so) on native, or as WebAssembly modules (.wasm) in the browser. The same source compiles to both targets.

What Plugins Can Do

Capability How
Add a dockable panel or overlay w.registerPanel(...) in .load
Set the editor status bar text w.setStatus(msg)
Write structured log messages w.log(level, tag, msg)
Read and write project files Plugin.Vfs
Trigger a UI redraw w.requestRefresh()
Place devices / wires w.placeDevice(...) / w.addWire(...)
Persist per-plugin key/value state w.setState(key, val) / w.getState(key)
Push commands to the host queue w.pushCommand(tag, payload)
Register keyboard shortcuts w.registerKeybind(key, mods, tag)
Query schematic instances and nets w.queryInstances() / w.queryNets()

Plugin Lifecycle

Runtime                             Plugin
  │                                   │
  │── process([load msg]) ───────────►│  registers panels, sets status
  │                                   │
  │   ... per frame ...               │
  │── process([tick msg]) ───────────►│  background work, state updates
  │── process([draw_panel msg]) ──────►│  emits ui_* widget messages
  │                                   │
  │── process([unload msg]) ─────────►│  cleanup

Return value = bytes written to output buffer. If buffer too small → return maxInt(usize), host retries with doubled buffer.

Language Support

Language Mechanism
Zig Direct import of PluginIF
C / C++ schemify_plugin.h header + addCPlugin / addCppPlugin
Rust schemify-plugin crate; export_plugin! macro
Python Pure .py files; addPythonPlugin deploys them
TinyGo schemify package; RunPlugin entry point

The ABI boundary is a plain C extern struct — any language that emits C-compatible shared-library exports works.

Deployment

Target Output Install location
Native (Linux) lib<Name>.so ~/.config/Schemify/<Name>/
Native (macOS) lib<Name>.dylib ~/.config/Schemify/<Name>/
Web (WASM) <Name>.wasm plugins/ dir, loaded by plugin_host.js

zig build run (via addNativeAutoInstallRunStep) copies the build output to the install directory and launches the host.

Included Plugins

EasyImport

Imports xschem .sch/.sym files, Virtuoso schematics, and TCL-based symbol libraries into Schemify's .chn format. Primary migration path for existing xschem projects.

# From CLI
schemify --cli import-xschem ./inverter.sch
# From UI: Plugins → EasyImport → Import XSchem File

PDKLoader (Volare)

Install and switch PDKs (SKY130, GF180, IHP-SG13G2) from inside the editor. Talks to the Volare registry. Manages $PDK path configuration.

Panel: PDK Manager (right sidebar)
Commands: :pdk install sky130, :pdk switch gf180

Optimizer

Bayesian optimization of circuit parameters. Given a schematic and a target metric (e.g., maximize phase margin), iteratively sweeps parameters and re-simulates.

Panel: Optimizer (right sidebar)
Workflow: select target metric → set param ranges → run → view convergence plot

Themes

Live theme switching via JSON theme files. Overrides colors, fonts, and spacing without restarting. Ships with built-in themes: Default Light, Default Dark, Tokyonight, Gruvbox, Catppuccin.

Panel: Theme Switcher (overlay)
Command: :theme tokyonight

GitBlame

Shows git commit info for components — who last changed each instance's properties and when. Useful for design review.

Hover instance → tooltip shows: "R1.value changed by alice@... 3 days ago"

Minimal Plugin

const Plugin = @import("PluginIF");

export fn schemify_process(
    in_ptr:  [*]const u8, in_len:  usize,
    out_ptr: [*]u8,       out_cap: usize,
) usize {
    var r = Plugin.Reader.init(in_ptr[0..in_len]);
    var w = Plugin.Writer.init(out_ptr[0..out_cap]);

    while (r.next()) |msg| {
        switch (msg) {
            .load => {
                w.registerPanel(.{
                    .id      = "demo",
                    .title   = "Demo Panel",
                    .vim_cmd = "demo",
                    .layout  = .right_sidebar,
                    .keybind = 'd',
                });
                w.setStatus("demo plugin loaded");
            },
            .draw_panel => {
                w.label("Hello from plugin!", 0);
            },
            else => {},
        }
    }

    return if (w.overflow()) std.math.maxInt(usize) else w.pos;
}

export const schemify_plugin: Plugin.Descriptor = .{
    .name        = "demo",
    .version_str = "0.1.0",
    .process     = schemify_process,
};

Plugin Examples

Language examples in plugins/examples/:

Directory Language
zig-demo/ Zig
c-demo/ C
cpp-demo/ C++
rust-demo/ Rust
python-demo/ Python
go-demo/ TinyGo

Each demonstrates: message parsing, panel registration, widget drawing, state persistence.